/***************************************************************************
 *   oboe.controllers.StateMachine					 *
 *   Copyright (C) 2011 by Felipe Manga					*
 *   lufeboma@gmail.com							*
 *									 *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the	   *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to	*
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:						 *
 *									 *
 *   The above copyright notice and this permission notice shall be	*
 *   included in all copies or substantial portions of the Software.	   *
 *									 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,	   *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF	*
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR	 *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.					   *
 ***************************************************************************/

package oboe.controllers;

import flash.display.Sprite;
import flash.events.Event;
import flash.utils.Dictionary;
import flash.utils.getTimer;

import oboe.controllers.debugConsole.DebugConsole;
import oboe.core.Controller;
import oboe.core.Oboe;
import oboe.math.Frame;

class StateMachine extends Controller
{
private var _baseTime : Int;
private var lastFPSTraceTime : Int;
private var frameCount : Int;
private var previousFPS : Int = -1;

private var isRoot:Bool;

private var states : Dictionary = new Dictionary();

private var activeState : Controller = null;
private var nextState : Controller = null;

public static inline var SIG_ONADDTOSTAGE:String = "onAddToStage";
public static inline var SIG_ONTICK:String = "onTick";
public static inline var SIG_ONEXITSTATE:String = "onExitState";
public static inline var SIG_ONENTERSTATE:String = "onEnterState";

public function new( mainSprite:Sprite, isRoot:Bool=true )
{
	super( mainSprite );
	
	this.isRoot = isRoot;
	
	if( isRoot )
	{
	Oboe.root = this;
	mainSprite.addEventListener( Event.ADDED_TO_STAGE, onAddToStage );
	mainSprite.addEventListener( Event.ENTER_FRAME, onEnterFrame );
	if( Oboe.flags["DEBUG"] || Oboe.flags["SHOW_CONSOLE"] )
	{
		this.addChild( new DebugConsole() );
	}
	}
}

public function addState( key:Object, state:Controller ):Void
{
	states[key] = state;
}

public function setState( key:Object ):Void
{
	this.nextState = states[key];
	if( !this.isRoot ) this.applyStateChanges();
}

public function applyStateChanges():Void
{
	if( this.nextState != this.activeState )
	{
	this.addChild( this.nextState );
	if( this.activeState )
	{
		this.activeState.message( SIG_ONEXITSTATE );
		this.removeChild( this.activeState );
	}
	this.activeState = this.nextState;
	this.activeState.message( SIG_ONENTERSTATE );
	}
}

private function onAddToStage(e:Event):Void
{
	if( Oboe.stage ) return;
	Oboe.stage = this.getDisplayObject().stage;
	if( !Oboe.flags["stageWidth"] ) Oboe.flags["stageWidth"] = Oboe.stage.stageWidth;
	if( !Oboe.flags["stageHeight"] ) Oboe.flags["stageHeight"] = Oboe.stage.stageHeight;
	
	this.shortSignal( SIG_ONADDTOSTAGE );
}

private function onEnterFrame( e:Event ):Void
{
	this.applyStateChanges();
	var now : Int = flash.utils.getTimer();
	var time : Float = (now - _baseTime)/1000.0;
	_baseTime = now;
	this.onPreTick( time );
	this.onTick( time );
	this.onPostTick( time );
	if( Oboe.flags["TRACE_FPS"] )
	{
	this.frameCount++;
	time = (now - lastFPSTraceTime)/1000.0; 
	if( time > 10 )
	{
		lastFPSTraceTime = now;
		now = int(this.frameCount/time+0.5);
		if( now != previousFPS )
		{
		trace( "FPS: ", now , "   CACHE SIZE:", Frame.getFrameCount() );
		previousFPS = now;
		}
		this.frameCount = 0;
	}
	}
}

private function onPreTick( time:Float ):Void
{
}
private function onTick( time:Float ):Void
{
	this.broadcastSignal( SIG_ONTICK, time);
}
private function onPostTick( time:Float ):Void
{
}
}